package com.tanhua.server.service;

import cn.hutool.core.collection.CollectionUtil;
import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.Constants;
import com.tanhua.commons.exception.TanHuaException;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.dubbo.api.mongo.CommentApi;
import com.tanhua.dubbo.api.mongo.MovementApi;
import com.tanhua.model.db.UserInfo;
import com.tanhua.model.enums.CommentType;
import com.tanhua.model.mongo.Comment;
import com.tanhua.model.mongo.Movement;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.MovementVo;
import com.tanhua.model.vo.MovementsVo;
import com.tanhua.model.vo.PageResult;
import com.tanhua.server.interceptor.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@Service
public class MovementService {

    @DubboReference
    private UserInfoApi userInfoApi;

    @Autowired
    private OssTemplate ossTemplate;

    @DubboReference
    private MovementApi movementApi;
    @DubboReference
    private CommentApi commentApi;

    @Autowired
    private MqMessageService mqMessageServicel;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    /**
     * 圈子管理业务处理层
     * @param movementVo
     * @param imageContent
     */
    public void addMovement(MovementVo movementVo, MultipartFile[] imageContent) {

        /**
         * 动态-发布
         * imageContent：多张图片文件对象 将图片上传阿里云 获取图片地址后 存入mongodb数据
         * imageContent:微信使用这个可以为空
         */
        try {
            ArrayList<String> medias = new ArrayList<>();
            //1将图片存入阿里云得到图片地址 List<String>集合
            if (imageContent != null && imageContent.length>0 ){
                for (MultipartFile multipartFile : imageContent) {

                    String originalFilename = multipartFile.getOriginalFilename();
                    //上传阿里云后图片地址
                    String imgUrl = ossTemplate.upload(originalFilename, multipartFile.getInputStream());
                    medias.add(imgUrl);
                }
            }

            //2构造Movement对象
            Movement movement = new Movement();
            BeanUtils.copyProperties(movementVo, movement);//动态文字 经纬度
            movement.setPid(11l);//推荐系统的自增id
            movement.setUserId(UserHolder.getUserId());//发布动态作者id
            movement.setLocationName(movementVo.getLocation());//中文地址名称
            movement.setMedias(medias);//图片地址信息已设置
            //3调用发布服务动态
            movement.setId(ObjectId.get());
            movementApi.add(movement);
            //往日志消息队列写消息
            mqMessageServicel.sendLogMessage(UserHolder.getUserId(),"0201","movement",movement.getId().toHexString());
            log.debug("**************写入日志消息成功了*********************");
        } catch (IOException e) {
            throw new TanHuaException(ErrorResult.error());
        }
    }

    /**
     * 我的动态
     * userId:为了当前此功能给其它地方使用
     * @param page
     * @param pagesize
     * @param userId
     * @return
     */
    public PageResult<MovementsVo> findPageMovement(Long page, Long pagesize, Long userId) {
        log.debug("******page{}*********pagesize{}*********userId{}*********", page, pagesize, userId);
        if (userId == null) {
            userId = UserHolder.getUserId();//如果没有传此值 用当前用户id查询我的动态数据
        }
        //1调用服务根据用户id分页查询动态表数据
        PageResult<Movement> pageResult = movementApi.findPageMovement(page, pagesize, userId);
        if (pageResult == null || CollectionUtils.isEmpty(pageResult.getItems())) {
            return null;//没有发布过任务动态数据
        }
        //2调用服务根据用户id查询用户详情
        UserInfo userInfo = userInfoApi.findUserInfo(userId);
        log.debug("******userInfo{}***********", userInfo.toString());
        //3基于用户详情与动态表数据构造VO返回
        List<MovementsVo> movementsVoList = new ArrayList<>();
        List<Movement> movementList = pageResult.getItems();
        for (Movement movement : movementList) {
            movementsVoList.add(MovementsVo.init(userInfo, movement));
        }
        log.debug("******getCounts{}***********************movementsVoList{}***", pageResult.getCounts(), movementsVoList.toString());
        return new PageResult<>(page, pagesize, pageResult.getCounts(), movementsVoList);
    }

    /**
     * 好友动态
     */
    public PageResult<MovementsVo> findPageMovementByFriend(Long page, Long pagesize) {
        Long loginUserId = UserHolder.getUserId();//当前登录用户id
        //1.调用服务分页查询动态表（服务中先查时间线再查动态表）
        PageResult<Movement> pageResult = movementApi.findPageMovementByFriend(page,pagesize,loginUserId);

        log.debug("******pageResult{}*********",pageResult.toString());
        //2.如果数据不存在 直接返回null
        if (pageResult == null || CollectionUtils.isEmpty(pageResult.getItems())) {
            return null;
        }
        return getMovementsVoPageResult(page, pagesize, pageResult);
    }


    /**
     * 推荐动态
     * @param page
     * @param pageSize
     * @return
     */
    public PageResult<MovementsVo> findPageMovementByRecommend(Long page, Long pageSize) {

        log.debug("*******findPageMovementByRecommend*****page{}********pageSize{}*********",page,pageSize);

        String key = Constants.MOVEMENTS_RECOMMEND + UserHolder.getUserId();
        //1根据key查redis中Pids(key不能随便改)
        String pidStrs = stringRedisTemplate.opsForValue().get(key);//pidStr以逗号分隔的 key=MOVEMENTS_RECOMMEND_1 value=1000个值
        log.debug("*******key*{}****pidStrs**{}********",key,pidStrs);
        //2如果没有值 构造随机查询10个动态数据
        PageResult<Movement> pageResult = new PageResult<>();
        if (StringUtils.isEmpty(pidStrs)) {
            pageResult = movementApi.findPageMovementByRecommend();
            pageResult.setCounts(10l);
            log.debug("******构造随机查询10个动态数据{}********",pageResult);
        }else {
            //3如果有值，根据Pids分页查询动态表数据
            //3.1 pidStr分页
            String[] recommendMovementIdsArr = StringUtils.split(pidStrs, ",");
            //1,2,3,4,5,.... 假设在有1000个Pids
            //String[] recommendMovementIdsArr = pidStr.split(",");
            // 计算分页的开始行
            long start = (page-1)*pageSize;//从哪条开始查询
            // 分页操作
            List<Long> pidList = Arrays.stream(recommendMovementIdsArr)
                    .skip(start).limit(pageSize).map(idStr -> Long.valueOf(idStr)).collect(Collectors.toList());
            log.debug("*********pidList{}**********",pidList);
            if(!CollectionUtils.isEmpty(pidList)) {
                pageResult = movementApi.findPageMovementByPids(pidList);
                //总记录数
                pageResult.setCounts((long) recommendMovementIdsArr.length);
            }
        }
        //4获取动态所有作者id调用服务获取用户详情
        //5.基于动态对象 用户详情对象构造分页VO返回
        return getMovementsVoPageResult(page, pageSize, pageResult);

    }

    /**
     * 好友动态 推荐动态公共方法
     * @param page
     * @param pagesize
     * @param pageResult
     * @return
     */
    private PageResult<MovementsVo> getMovementsVoPageResult(Long page, Long pagesize, PageResult<Movement> pageResult) {
        //3.如果数据存在 获取出所有动态作者ids
        List<Movement> movementList = pageResult.getItems();
        List<Long> movementUserIds = movementList.stream().map(Movement::getUserId).collect(Collectors.toList());
        List<MovementsVo> movementsVoList = new ArrayList<>();
        if (!CollectionUtil.isEmpty(movementUserIds)) {
            //4.根据动态作者ids查询作者详情
            Map<Long, UserInfo> userInfoMap = userInfoApi.findByCondition(movementUserIds, null);

            //5.基于动态数据以及用户详情 构造分页vo返回
            for (Movement movement : movementList) {
                UserInfo userInfo = userInfoMap.get(movement.getUserId());
                movementsVoList.add(MovementsVo.init(userInfo, movement));
            }
        }
        log.debug("******getCounts{}***********************movementsVoList{}***", pageResult.getCounts(), movementsVoList.toString());
        return new PageResult<>(page,pagesize,pageResult.getCounts(),movementsVoList);
    }

    /**
     * 动态点赞
     */
    public Integer like(String publishId) {
        //1.调用服务保存点赞记录 动态评论表中
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));//动态id
        comment.setCommentType(CommentType.LIKE.getType());//评论类型，1-点赞，2-评论，3-喜欢
        comment.setUserId(UserHolder.getUserId());//评论人用户id

        Integer count = commentApi.add(comment);
        //2.将当前用户针对此动态的点赞记录写入redis(好友 推荐动态查询需要查redis)
        String key = Constants.MOVEMENTS_INTERACT_KEY + publishId;//大Key 相当于表(针对某个动态操作 全部在这个key中)
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId(); //小key（针对动态操作 点赞、喜欢等）
        stringRedisTemplate.opsForHash().put(key,hashKey,"1");

        mqMessageServicel.sendLogMessage(UserHolder.getUserId(),"0203","movement",publishId);
        log.debug("**************写入日志消息成功了*********************");
        return count;
    }

    /**
     * 单条动态
     * publishId:动态表主键id
     */
    public MovementsVo findMovement(String publishId) {
        //根据动态主键id调用服务查询动态对象
        Movement movement = movementApi.findMovement(publishId);
        UserInfo userInfo = userInfoApi.findUserInfo(movement.getUserId());
        return MovementsVo.init(userInfo, movement);
    }

    /**
     * 单条动态
     * publishId:动态表主键id
     */
    public Integer dislike(String publishId) {
        //1.调用服务删除点赞记录 从动态评论表中
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));//动态id
        comment.setCommentType(CommentType.LIKE.getType());//评论类型，1-点赞，2-评论，3-喜欢
        comment.setUserId(UserHolder.getUserId());//评论人用户id
        Integer count = commentApi.delete(comment);
        //2.将当前用户针对此动态的点赞记录从redis删除
        String key = Constants.MOVEMENTS_INTERACT_KEY + publishId;//大Key 相当于表(针对某个动态操作 全部在这个key中)
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId(); //小key（针对动态操作 点赞、喜欢等）
        stringRedisTemplate.opsForHash().delete(key,hashKey);
        return count;
    }
}
